/*
 * tsymbol.c
 *
 *  Created on: Jan 10, 2016
 *      Author: root
 */

#include <string.h>
#include <limits.h>
#include <stdio.h>
#include "../basic/operator.h"

/*
// (in-global-package)
Cell* op_in_global_package(Scheme *sc) {
	sc->package = G_NIL;
	return s_return_helper(sc, &g_true);
}

// (in-package "funny.core.basis")
// (in-package "funny.core.basis" symbol)
Cell* op_in_package(Scheme *sc) {
	Cell *package = first(sc->args);
	Cell *symbol = second(sc->args);
	TYPE_CHECK(sc, package, TYPE_STRING);
	Cell *result = &g_true;
	if (symbol == G_NIL) {
		sc->package = package;
	} else {
		// result = find_symbol_in_package();
	}
	return s_return_helper(sc, result);
}
*/

char *symbol_name(Cell* sym) {
	return sym->_string;
}

static Cell* find_symbol(Scheme *sc, const char *name) {
    int location = hash_fn(name, sc->symbols->_longValue);
    Cell* sym_list;
    for (sym_list = get_vector_item(sc->symbols, location); sym_list != G_NIL; sym_list = cdr(sym_list)) {
        char *s = symbol_name(car(sym_list));
        if (strcmp(name, s) == 0)
            return car(sym_list); //返回一个符号
    }
    return G_NIL;
}

static Cell* add_symbol(Scheme *sc, const char *name) {
    Cell* sym = cons(sc, G_NIL, G_NIL);
    sym->_type = SYMBOL_TYPE; //类型为符号
    sym->_name = name;
    sym->_string = name;
    set_immutable(sym);
    int location = hash_fn(name, sc->symbols->_longValue);
    set_vector_item(sc->symbols, location, immutable_cons(sc, sym, get_vector_item(sc->symbols, location))); //将新的符号加入链表头部
    return sym;
}

//添加一个符号，如果有这个符号，就返回已有的那个
Cell* make_symbol(Scheme *sc, const char *name) {
	Cell* sym = find_symbol(sc, name);
	if (sym != G_NIL)
		return sym;
	return add_symbol(sc, name);
}

// (defined? var_name)
// (defined? var_name env)
Cell* op_defp(Scheme *sc) {
    LOG_INPUT(sc, "atoms/symbol", "op_defp");

	Cell *env;
	if (rest(sc->args) != G_NIL)
		env = second(sc->args);
	else
		env = sc->env;

    Cell* value = lookup_variable_value(sc, env, first(sc->args));
    int is_true = !type_of(sc, value, EXCEPTION_TYPE);
	sc->returnValue = (is_true) ? G_TRUE : G_FALSE;

    LOG_OUTPUT(sc, "atoms/symbol", "op_defp");
	return pop_callstack(sc);
}


//生成一个名字唯一的符号
static Cell* gensym(Scheme *sc) {
    static long s_gensym_cnt = 0;
    for (; s_gensym_cnt < LONG_MAX; s_gensym_cnt++) {
        char name[40];
        snprintf(name, 40, "sgensym-%ld", s_gensym_cnt);
        Cell* sym = find_symbol(sc, name);
        if (sym != G_NIL)
            continue;
        return add_symbol(sc, name);
    }
    return G_NIL;
}

// (gensym)
Cell* op_gensym(Scheme *sc) {
    sc->returnValue = gensym(sc);
    return pop_callstack(sc);
}

void init_symbol_operators(Scheme *sc) {
	ADD_OPERATOR(sc, "defined?", defp);
    ADD_OPERATOR(sc, "gensym", gensym);
}

void init_symbol_constants(Scheme *sc) {
    cell_lambda = make_constant(sc, KEYWORD_LAMBDA);
    cell_quote = make_constant(sc, KEYWORD_QUOTE);
    cell_this = make_constant(sc, KEYWORD_THIS);


    //cell_symbol_lambda = make_symbol(sc, SYMBOL_LAMBDA);
	//cell_symbol_quote = make_symbol(sc, SYMBOL_QUOTE);
	//cell_symbol_this = make_symbol(sc, SYMBOL_THIS);
}

//symbol->string
